{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。\n",
    "\n",
    "- 异常处理: 本站Python教程会具体介绍。\n",
    "- 断言(Assertions):本站Python教程会具体介绍。\n",
    "\n",
    "## 什么是异常？\n",
    "\n",
    "其实已经在前面遇见过异常了，比如：使用一个没有定义的变量，就会产生一个名字错误的异常；将一个字符串对象和数值对象相加，就会产生类型错误异常。\n",
    "\n",
    "什么是异常？**异常是程序在执行时发生的事件，它会打断指令的正常流程。** 发生一个异常时，表示发生了一个 python 自身无法处理的一个错误。\n",
    "\n",
    "异常即是一个事件，该事件会在程序执行过程中发生，影响了程序的正常执行。\n",
    "\n",
    "一般情况下，在Python无法正常处理程序时就会发生一个异常。\n",
    "\n",
    "异常是Python对象，表示一个错误。\n",
    "\n",
    "当Python脚本发生异常时我们需要捕获处理它，否则程序会终止执行。\n",
    "\n",
    "简单理解就是程序发生了我们意料之外的错误，发生异常的情况很多，比如网络失败、磁盘文件失败、使用了2个不同类型的对象做运算等。并且大部分是编码时不可预知是否会发生，这和代码当时运行环境有很大关联，有可能发生，也有可能不会发生。\n",
    "\n",
    "## python标准异常\n",
    "\n",
    "python 已经内置了很多标准的异常类。\n",
    "\n",
    "| 异常名称                  | 描述                                               |\n",
    "| ------------------------- | -------------------------------------------------- |\n",
    "|                           |                                                    |\n",
    "| BaseException             | 所有异常的基类                                     |\n",
    "| SystemExit                | 解释器请求退出                                     |\n",
    "| KeyboardInterrupt         | 用户中断执行(通常是输入^C)                         |\n",
    "| Exception                 | 常规错误的基类                                     |\n",
    "| StopIteration             | 迭代器没有更多的值                                 |\n",
    "| GeneratorExit             | 生成器(generator)发生异常来通知退出                |\n",
    "| StandardError             | 所有的内建标准异常的基类                           |\n",
    "| ArithmeticError           | 所有数值计算错误的基类                             |\n",
    "| FloatingPointError        | 浮点计算错误                                       |\n",
    "| OverflowError             | 数值运算超出最大限制                               |\n",
    "| ZeroDivisionError         | 除(或取模)零 (所有数据类型)                        |\n",
    "| AssertionError            | 断言语句失败                                       |\n",
    "| AttributeError            | 对象没有这个属性                                   |\n",
    "| EOFError                  | 没有内建输入,到达EOF 标记                          |\n",
    "| EnvironmentError          | 操作系统错误的基类                                 |\n",
    "| IOError                   | 输入/输出操作失败                                  |\n",
    "| OSError                   | 操作系统错误                                       |\n",
    "| WindowsError              | 系统调用失败                                       |\n",
    "| ImportError               | 导入模块/对象失败                                  |\n",
    "| LookupError               | 无效数据查询的基类                                 |\n",
    "| IndexError                | 序列中没有此索引(index)                            |\n",
    "| KeyError                  | 映射中没有这个键                                   |\n",
    "| MemoryError               | 内存溢出错误(对于Python 解释器不是致命的)          |\n",
    "| NameError                 | 未声明/初始化对象 (没有属性)                       |\n",
    "| UnboundLocalError         | 访问未初始化的本地变量                             |\n",
    "| ReferenceError            | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |\n",
    "| RuntimeError              | 一般的运行时错误                                   |\n",
    "| NotImplementedError       | 尚未实现的方法                                     |\n",
    "| SyntaxError               | Python 语法错误                                    |\n",
    "| IndentationError          | 缩进错误                                           |\n",
    "| TabError                  | Tab 和空格混用                                     |\n",
    "| SystemError               | 一般的解释器系统错误                               |\n",
    "| TypeError                 | 对类型无效的操作                                   |\n",
    "| ValueError                | 传入无效的参数                                     |\n",
    "| UnicodeError              | Unicode 相关的错误                                 |\n",
    "| UnicodeDecodeError        | Unicode 解码时的错误                               |\n",
    "| UnicodeEncodeError        | Unicode 编码时错误                                 |\n",
    "| UnicodeTranslateError     | Unicode 转换时错误                                 |\n",
    "| Warning                   | 警告的基类                                         |\n",
    "| DeprecationWarning        | 关于被弃用的特征的警告                             |\n",
    "| FutureWarning             | 关于构造将来语义会有改变的警告                     |\n",
    "| OverflowWarning           | 旧的关于自动提升为长整型(long)的警告               |\n",
    "| PendingDeprecationWarning | 关于特性将会被废弃的警告                           |\n",
    "| RuntimeWarning            | 可疑的运行时行为(runtime behavior)的警告           |\n",
    "| SyntaxWarning             | 可疑的语法的警告                                   |\n",
    "| UserWarning               | 用户代码生成的警告                                 |\n",
    "\n",
    "\n",
    "\n",
    "# 异常捕捉\n",
    "\n",
    "捕捉异常可以使用try/except语句。\n",
    "\n",
    "try/except语句用来检测try语句块中的错误，从而让except语句捕获异常信息并处理。\n",
    "\n",
    "如果你不想在异常发生时结束你的程序，只需在try里捕获它。\n",
    "\n",
    "语法：\n",
    "\n",
    "```\n",
    "try:\n",
    "    <语句>        #运行别的代码\n",
    "except <名字>：\n",
    "    <语句>        #如果在try部份引发了'name'异常\n",
    "except <名字>，<数据>:\n",
    "    <语句>        #如果引发了'name'异常，获得附加的数据\n",
    "else:\n",
    "    <语句>        #如果没有异常发生\n",
    "```\n",
    "\n",
    "try的工作原理是，当开始一个try语句后，python就在当前程序的上下文中作标记，这样当异常出现时就可以回到这里，try子句先执行，接下来会发生什么依赖于执行时是否出现异常。\n",
    "\n",
    "- 如果当try后的语句执行时发生异常，python就跳回到try并执行第一个匹配该异常的except子句，异常处理完毕，控制流就通过整个try语句（除非在处理异常时又引发新的异常）。\n",
    "- 如果在try后的语句里发生了异常，却没有匹配的except子句，异常将被递交到上层的try，或者到程序的最上层（这样将结束程序，并打印缺省的出错信息）。\n",
    "- 如果在try子句执行时没有发生异常，python将执行else语句后的语句（如果有else的话），然后控制流通过整个try语句。\n",
    "\n",
    "实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "must be str, not int",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-e29823995ef5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m\"a\"\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: must be str, not int"
     ]
    }
   ],
   "source": [
    "\"a\"+1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "类型错误\n",
      "must be str, not int\n"
     ]
    }
   ],
   "source": [
    "# 处理异常\n",
    "try:\n",
    "     \"a\"+1\n",
    "except NameError:\n",
    "    print(\"未定义变量处理\")\n",
    "    print(e)\n",
    "except TypeError as e:\n",
    "    print(\"类型错误\")\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 语法错误\n",
    "\n",
    "Python 的语法错误或者称之为解析错，是初学者经常碰到的，如下实例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-3-2b688bc740d7>, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-3-2b688bc740d7>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m    while True print('Hello world')\u001b[0m\n\u001b[0m                   ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "while True print('Hello world')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用except而不带任何异常类型\n",
    "你可以不带任何异常类型使用except，如下实例：\n",
    "\n",
    "```\n",
    "try:\n",
    "    正常的操作\n",
    "   ......................\n",
    "except:\n",
    "    发生异常，执行这块代码\n",
    "   ......................\n",
    "else:\n",
    "    如果没有异常执行这块代码\n",
    "以上方式try-except语句捕获所有发生的异常。但这不是一个很好的方式，我们不能通过该程序识别出具体的异常信息。因为它捕获所有的异常。\n",
    "\n",
    "```\n",
    "\n",
    "使用except而带多种异常类型\n",
    "你也可以使用相同的except语句来处理多个异常信息，如下所示：\n",
    "\n",
    "```\n",
    "try:\n",
    "    正常的操作\n",
    "   ......................\n",
    "except(Exception1[, Exception2[,...ExceptionN]]]):\n",
    "   发生以上多个异常中的一个，执行这块代码\n",
    "   ......................\n",
    "else:\n",
    "    如果没有异常执行这块代码\n",
    "```\n",
    "\n",
    "try-finally 语句\n",
    "try-finally 语句无论是否发生异常都将执行最后的代码。\n",
    "```\n",
    "try:\n",
    "    <语句>\n",
    "finally:\n",
    "    <语句>    #退出try时总会执行\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Error: 没有找到文件或读取文件失败\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    fh = open(\"testfile\", \"w\")\n",
    "    fh.write(\"这是一个测试文件，用于测试异常!!\")\n",
    "finally:\n",
    "    print(\"Error: 没有找到文件或读取文件失败\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "关闭文件\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    fh = open(\"testfile\", \"w\")\n",
    "    try:\n",
    "        fh.write(\"这是一个测试文件，用于测试异常!!\")\n",
    "    finally:\n",
    "        print (\"关闭文件\")\n",
    "        fh.close()\n",
    "except IOError:\n",
    "    print (\"Error: 没有找到文件或读取文件失败\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当在try块中抛出一个异常，立即执行finally块代码。\n",
    "\n",
    "finally块中的所有语句执行后，异常被再次触发，并执行except块代码。\n",
    "\n",
    "参数的内容不同于异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OS error: [Errno 2] No such file or directory: 'myfile.txt'\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    f = open('myfile.txt')\n",
    "    s = f.readline()\n",
    "    i = int(s.strip())\n",
    "except OSError as err:\n",
    "    print(\"OS error: {0}\".format(err))\n",
    "except ValueError:\n",
    "    print(\"Could not convert data to an integer.\")\n",
    "except:\n",
    "    print(\"Unexpected error:\", sys.exc_info()[0])\n",
    "    raise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## raise 触发异常\n",
    "\n",
    "可以使用raise语句自己触发异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "Exception",
     "evalue": "Invalid level!",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mException\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-7-4b6d1cc080ee>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid level!\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mException\u001b[0m: Invalid level!"
     ]
    }
   ],
   "source": [
    "raise Exception(\"Invalid level!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 自定义异常\n",
    "\n",
    "通过创建一个新的异常类，程序可以命名它们自己的异常。异常应该是典型的继承自Exception类，通过直接或间接的方式。\n",
    "\n",
    "以下为与RuntimeError相关的实例,实例中创建了一个类，基类为RuntimeError，用于在异常触发时输出更多的信息。\n",
    "\n",
    "在try语句块中，用户自定义的异常后执行except块语句，变量 e 是用于创建Networkerror类的实例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "arg: Bad hostname\n",
      "('B', 'a', 'd', ' ', 'h', 'o', 's', 't', 'n', 'a', 'm', 'e')\n"
     ]
    }
   ],
   "source": [
    "# 自定义异常\n",
    "class Networkerror(RuntimeError):\n",
    "    def __init__(self, arg):\n",
    "        print(\"arg: \"+ arg)\n",
    "        self.args = arg\n",
    "        \n",
    "# 使用异常\n",
    "try:\n",
    "    raise Networkerror(\"Bad hostname\")\n",
    "except Networkerror as e:\n",
    "    print(e.args)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "默认异常处理\n",
    "\n",
    "处理后始终执行操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "arg: Bad hostname\n",
      "('B', 'a', 'd', ' ', 'h', 'o', 's', 't', 'n', 'a', 'm', 'e')\n",
      "almost execute\n",
      "almost execute2\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    raise Networkerror(\"Bad hostname\")\n",
    "except Networkerror as e:\n",
    "    print(e.args)\n",
    "except:\n",
    "    print(\"default process\")\n",
    "finally:\n",
    "    print(\"almost execute\")\n",
    "    \n",
    "print(\"almost execute2\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 预定义的清理行为\n",
    "一些对象定义了标准的清理行为，无论系统是否成功的使用了它，一旦不需要它了，那么这个标准的清理行为就会执行。\n",
    "\n",
    "这面这个例子展示了尝试打开一个文件，然后把内容打印到屏幕上:\n",
    "\n",
    "```\n",
    "for line in open(\"myfile.txt\"):\n",
    "    print(line, end=\"\")\n",
    "```\n",
    "\n",
    "以上这段代码的问题是，当执行完毕后，文件会保持打开状态，并没有被关闭。\n",
    "\n",
    "关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:\n",
    "\n",
    "```\n",
    "with open(\"myfile.txt\") as f:\n",
    "    for line in f:\n",
    "        print(line, end=\"\")\n",
    "```\n",
    "\n",
    "以上这段代码执行完毕后，就算在处理过程中出问题了，文件 f 总是会关闭。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
